#include "datacenter.h"
#include <QStandardPaths>
#include <QDir>
#include <QJsonObject>
#include <QJsonDocument>
#include "../toast.h"


namespace model
{
DataCenter* DataCenter::instance = nullptr;
DataCenter::DataCenter()
    :netClient(this),
    sessionMemberLists(new QHash<QString,QList<UserInfo>>),
    recentMessages(new QHash<QString,QList<Message>>),
    unreadMessageCount(new QHash<QString,int>)
{
    // 此处只是把这几个 hash 类型的属性 new 出实例. 其他的 QList 类型的属性, 都暂时不实例化.
    // 主要是为了使用 nullptr 表示 "非法状态"
    // 对于 hash 来说, 不关心整个 QHash 是否是 nullptr, 而是关心, 某个 key 对应的 value 是否存在
    // 通过 key 是否存在, 也能表示该值是否有效.
    loadDataFile();
}
DataCenter::~DataCenter()
{
    delete myself;
    delete friendList;
    delete sessionList;
    delete sessionMemberLists;
    delete applyList;
    delete recentMessages;
    delete unreadMessageCount;
    delete searchUserResult;
    delete searchMessageResult;
}
DataCenter* DataCenter::getInstance()
{
    if(!instance)
        instance = new DataCenter;
    return instance;
}

void DataCenter::initWebSocket()
{
    netClient.initWebSocket();
}

void DataCenter::closeWebSocket()
{
    netClient.closeWebSocket();
}

void DataCenter::initDataFile()
{
    //构造数据文件的路径，设置在appData区
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath+QDir::separator()+"chatClientPlus.json";
    LOG()<<"filePath="<<filePath;

    QDir dir;
    if(dir.exists(basePath)==false)
        dir.mkpath(basePath);

    //创建文件，并写入初始内容
    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
    {
        LOG()<<"打开文件失败!"<<file.errorString();
        return;
    }

    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();

}

void DataCenter::saveDataFile()
{
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath+QDir::separator()+"chatClientPlus.json";

    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly|QIODevice::Text))
    {
        LOG()<<"打开文件失败!"<<file.errorString();
        return;
    }

    QJsonObject jsonObj;
    jsonObj["loginSessionId"] = loginSessionId;

    QJsonObject jsonUnread;
    for(auto it = unreadMessageCount->begin();it!=unreadMessageCount->end();it++)
        jsonUnread[it.key()] = it.value();
    jsonObj["unread"] = jsonUnread;

    QJsonDocument jsonDoc(jsonObj);
    file.write(jsonDoc.toJson());

    file.close();
}

void DataCenter::loadDataFile()
{
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath+QDir::separator()+"chatClientPlus.json";
    QFileInfo fileInfo(filePath);
    if(fileInfo.exists()==false)
        initDataFile();


    //读方式打开文件
    QFile file(filePath);
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        LOG()<<"打开文件失败!"<<file.errorString();
        return;
    }

    //读文件，转化为Json,然后转化为数据结构的内容
    QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
    if(jsonDoc.isNull())
    {
        LOG()<<"解析Json文件失败";
        file.close();
        return;
    }

    QJsonObject obj = jsonDoc.object();
    loginSessionId = obj["loginSessionId"].toString();
    LOG()<<"loginSessionId="<<loginSessionId;

    QJsonObject unreadObj = obj["unread"].toObject();
    unreadMessageCount->clear();

    for(auto it = unreadObj.begin();it!=unreadObj.end();it++)
        unreadMessageCount->insert(it.key(),it.value().toInt());

    file.close();
}

void DataCenter::getMyselfAsync()
{
    //调用NetClient处理数据
    netClient.getMyself(loginSessionId);
}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::resetMyself(std::shared_ptr<zzy_mims::GetUserInfoRsp> resp)
{
    if(!myself)
        myself = new UserInfo();
    const zzy_mims::UserInfo& userInfo = resp->userInfo();
    myself->load(userInfo);
}

void DataCenter::getSessionListAsync()
{
    netClient.getSessionList(loginSessionId);
}

void DataCenter::resetSessionList(std::shared_ptr<zzy_mims::GetChatSessionListRsp> resp)
{
    if(!sessionList)
        sessionList = new QList<SessionInfo>;
    sessionList->clear();

    auto& PBSessionList = resp->chatSessionInfoList();
    for(auto& s:PBSessionList)
    {
        SessionInfo sessionInfo;
        sessionInfo.load(s);
        sessionList->push_back(sessionInfo);
    }

}

void DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

void DataCenter::resetFriendList(std::shared_ptr<zzy_mims::GetFriendListRsp> resp)
{
    if(!friendList)
        friendList = new QList<UserInfo>;
    friendList->clear();

    auto& PBFriendList = resp->friendList();
    for(auto& f:PBFriendList)
    {
        UserInfo userInfo;
        userInfo.load(f);
        friendList->push_back(userInfo);
    }
}

void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}
void DataCenter::resetApplyList(std::shared_ptr<zzy_mims::GetPendingFriendEventListRsp> rsp)
{
    if(!applyList)
        applyList = new QList<UserInfo>;
    applyList->clear();
    for(auto& e:rsp->event())
    {
        UserInfo userInfo;
        userInfo.load(e.sender());
        applyList->push_back(userInfo);
    }
}

void DataCenter::getRecentMessageListAsync(const QString &sessionId, bool isUpdateUI)
{
    netClient.getRecentMessageList(loginSessionId,sessionId,isUpdateUI);
}

void DataCenter::resetRecentMessageList(std::shared_ptr<zzy_mims::GetRecentMsgRsp> rsp,const QString& sessionId)
{
    auto& recentMsgList = (*recentMessages)[sessionId];
    recentMsgList.clear();
    for(auto& m:rsp->msgList())
    {
        Message message;
        message.load(m);
        recentMsgList.push_back(message);
    }
}

void DataCenter::sendTextMessageAsync(const QString &sessionId, const QString &content)
{
    netClient.sendMessage(loginSessionId,sessionId,MessageType::TEXT_TYPE,content.toUtf8(),"");
}

void DataCenter::sendImageMessageAsync(const QString &sessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId,sessionId,model::MessageType::IMAGE_TYPE,content,"");
}

void DataCenter::sendFileMessageAsync(const QString &sessionId, const QByteArray &content,const QString& fileName)
{
    netClient.sendMessage(loginSessionId,sessionId,model::MessageType::FILE_TYPE,content,fileName);
}

void DataCenter::sendSpeechMessageAsync(const QString &sessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId,sessionId,model::MessageType::SPEECH_TYPE,content,"");
}

void DataCenter::changeNicknameAsync(const QString &nickname)
{
    netClient.changeNickname(loginSessionId,nickname);
}

void DataCenter::changeDescAsync(const QString &desc)
{
    netClient.changeDesc(loginSessionId,desc);
}

void DataCenter::getVertifyCodeAsync(const QString &phone)
{
    netClient.getVertifyCode(phone);
}

void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId,phone,verifyCodeId,verifyCode);
}

void DataCenter::changeAvatarAsync(const QByteArray &avatar)
{
    netClient.changeAvatar(loginSessionId,avatar);
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId,userId);
}

void DataCenter::removeFriend(const QString &userId)
{
    if(!friendList||!sessionList||userId=="")
        return;
    friendList->removeIf([=](const UserInfo& f)
    {
        return f.userId==userId;
    });
    sessionList->removeIf([=](const SessionInfo& s)
    {
        if(s.userId==userId)
        {
            //对应的槽函数在mainWidget
            if(s.chatSessionId==currentSessionId)
                emit clearCurrentSession();
            return true;
        }
        return false;
    });
}

void DataCenter::sendApplyAsync(const QString &userId)
{
    netClient.sendApply(loginSessionId,userId);
}

model::UserInfo DataCenter::removeFromApplyList(const QString &userId)
{

    model::UserInfo ret;
    //事实上applyList是一定不是nullptr的，因为触发这个函数一定是在apply界面的，也就一定会加载
    if(applyList)
    {
        applyList->removeIf([&](const model::UserInfo& userInfo)
        {
            if(userInfo.userId==userId)
            {
                ret = userInfo;
                return true;
            }
            return false;
        });
    }
    return ret;
}

void DataCenter::addFriend(const model::UserInfo &userInfo)
{
    if(!friendList) return;
    friendList->push_front(userInfo);
}

void DataCenter::addSession(const QString &sessionId, const UserInfo &userInfo)
{
    if(!sessionList) return;
    model::SessionInfo sInfo;
    sInfo.chatSessionId = sessionId;
    sInfo.chatSessionName=userInfo.nickname;
    sInfo.avatar=userInfo.avatar;
    sInfo.lastMessage = model::Message();
    sInfo.userId =userInfo.userId;
    sessionList->push_front(sInfo);
}

void DataCenter::addSession(const zzy_mims::ChatSessionInfo &sessionInfo)
{
    model::SessionInfo sInfo;
    sInfo.load(sessionInfo);
    sessionList->push_front(sInfo);
}

void DataCenter::processFriendApplyAsync(bool isAgree,const QString& applyUserId)
{
    netClient.processFriendApply(loginSessionId,applyUserId,isAgree);
}

void DataCenter::sreachUserAsync(const QString &key)
{
    netClient.sreachUser(loginSessionId,key);
}

void DataCenter::resetSearchResult(const QList<zzy_mims::UserInfo> &userList)
{
    if(!searchUserResult)
        searchUserResult = new QList<model::UserInfo>;
    searchUserResult->clear();

    for(auto u:userList)
    {
        model::UserInfo userInfo;
        userInfo.load(u);
        searchUserResult->push_back(userInfo);
    }
}

void DataCenter::createSessionAsync(const QList<QString> &memberList)
{
    netClient.createSession(loginSessionId,memberList);
}

void DataCenter::getSessionMemberListAsync(const QString &sessionId)
{
    netClient.getSessionMemberList(loginSessionId,sessionId);
}

void DataCenter::resetSessionMemberList(const QString& sessionId,const QList<zzy_mims::UserInfo> &memberList)
{
    UserInfo userInfo;
    for(int i =0;i<memberList.size();i++)
    {
        userInfo.load(memberList[i]);
        (*sessionMemberLists)[sessionId].push_back(userInfo);
    }
    return;
}

void DataCenter::getSearchHistoryListAsync(const QString &key)
{
    if(key.isEmpty())
    {
        Toast::showMessage("搜索结果为空，无法搜索");
        return;
    }
    netClient.getSearchHistoryList(loginSessionId,key);
}

void DataCenter::resetSearchHistoryList(const QList<zzy_mims::MessageInfo> &msgList)
{
    if(!searchMessageResult)
        searchMessageResult = new QList<Message>;
    searchMessageResult->clear();
    for(auto& m:msgList)
    {
        model::Message msg;
        msg.load(m);
        searchMessageResult->push_back(msg);
    }
}

void DataCenter::getSearchHistoryListByTimeAsync(const QDateTime &beginTime, const QDateTime &endTime)
{
    if(beginTime>endTime)
    {
        Toast::showMessage("搜索的时间范围不合法");
        return;
    }
    netClient.getSearchHistoryListByTime(beginTime,endTime,loginSessionId);

}

void DataCenter::userLoginAsync(const QString &name, const QString &pswd)
{
    if(pswd.size()<6||pswd.size()>16)
    {
        Toast::showMessage("密码错误");
        return;
    }
    netClient.userLogin(name,pswd);
}

void DataCenter::userRegisterAsync(const QString &name, const QString &pswd)
{
    if(pswd.size()<6||pswd.size()>16)
    {
        Toast::showMessage("密码错误");
        return;
    }
    netClient.userRegister(name,pswd);
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.phoneLogin(phone,verifyCodeId,verifyCode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.phoneRegister(phone,verifyCodeId,verifyCode);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    netClient.getSingleFile(loginSessionId,fileId);
}

void DataCenter::speechConvertTextAsync(const QString &fileId, const QByteArray &content)
{
    netClient.speechConvertText(loginSessionId,fileId,content);
}

}//model
















